package lol.clann.minecraft.springboot.plugin.core.config.configurate;

import com.google.auto.service.AutoService;
import lol.clann.minecraft.springboot.api.spi.sbp.ApplicationRunListener;
import relocate.com.google.common.collect.Sets;
import relocate.com.google.common.reflect.TypeToken;
import relocate.ninja.leaping.configurate.ConfigurationNode;
import relocate.ninja.leaping.configurate.objectmapping.ObjectMappingException;
import relocate.ninja.leaping.configurate.objectmapping.serialize.TypeSerializer;
import relocate.ninja.leaping.configurate.objectmapping.serialize.TypeSerializers;
import org.springframework.boot.SpringApplication;

import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 * 让configurate支持set
 *
 * @author pyz
 * @date 2018/8/13 下午9:53
 */
@AutoService(ApplicationRunListener.class)
public class SerializerSet implements TypeSerializer<Set<?>>, ApplicationRunListener {

    @Override
    public void starting(SpringApplication application) {
        TypeSerializers.getDefaultSerializers().registerPredicate(typeToken -> Set.class.isAssignableFrom(typeToken.getRawType()), this);
    }

    @Override
    public Set<?> deserialize(TypeToken<?> type, ConfigurationNode value) throws ObjectMappingException {
        if (!(type.getType() instanceof ParameterizedType)) {
            throw new ObjectMappingException("Raw types are not supported for collections");
        } else {
            TypeToken<?> entryType = type.resolveType(Set.class.getTypeParameters()[0]);
            TypeSerializer entrySerial = value.getOptions().getSerializers().get(entryType);
            if (entrySerial == null) {
                throw new ObjectMappingException("No applicable type serializer for type " + entryType);
            } else if (!value.hasListChildren()) {
                Object unwrappedVal = value.getValue();
                return unwrappedVal != null ? Sets.newHashSet(new Object[]{entrySerial.deserialize(entryType, value)}) : new HashSet<>();
            } else {
                List<? extends ConfigurationNode> values = value.getChildrenList();
                List<Object> ret = new ArrayList(values.size());
                Iterator var7 = values.iterator();
                while (var7.hasNext()) {
                    ConfigurationNode ent = (ConfigurationNode) var7.next();
                    ret.add(entrySerial.deserialize(entryType, ent));
                }
                return new HashSet<>(ret);
            }
        }
    }

    @Override
    public void serialize(TypeToken<?> type, Set<?> obj, ConfigurationNode value) throws ObjectMappingException {
        if (!(type.getType() instanceof ParameterizedType)) {
            throw new ObjectMappingException("Raw types are not supported for collections");
        } else {
            TypeToken<?> entryType = type.resolveType(Set.class.getTypeParameters()[0]);
            TypeSerializer entrySerial = value.getOptions().getSerializers().get(entryType);
            if (entrySerial == null) {
                throw new ObjectMappingException("No applicable type serializer for type " + entryType);
            } else {
                value.setValue(new ArrayList<>());
                Iterator var6 = obj.iterator();
                while (var6.hasNext()) {
                    Object ent = var6.next();
                    entrySerial.serialize(entryType, ent, value.getAppendedNode());
                }
            }
        }
    }

}
